<template>
  <el-form ref="formRef" :model="formData" label-width="80">
    <div class="group-name">
      <el-form-item
        label="分组名称"
        class="group-name_input"
        prop="customerGroupName"
        :rules="[{ required: true, message: '请输入分组名称', trigger: 'blur' }]"
      >
        <el-input placeholder="请输入" :maxlength="20" v-model="formData.customerGroupName" show-word-limit clearable />
      </el-form-item>
      <el-form-item label="排序">
        <el-input class="group-name_sort" type="number" v-model="formData.orderNum" :min="0" @input="inputSort" />
      </el-form-item>
    </div>
    <div class="group-name_tip">请输入分组名称，该名称会在“我的客户”筛选项出现</div>
    <el-form-item label="备注">
      <el-input type="textarea" placeholder="请输入" v-model="formData.desc" :autosize="{ minRows: 3 }" />
    </el-form-item>
    <el-form-item label="筛选条件">
      <el-button type="primary" link :icon="Plus" @click="handelAddGroup">条件组</el-button>
    </el-form-item>

    <div class="group-container" v-for="(item, conditionsIndex) in formData.conditions" v-loading="isGroupLoading">
      <div class="group-not-type" v-if="conditionsIndex === 0">当</div>
      <el-select v-else class="group-type" placeholder="" v-model="item.groupType">
        <el-option label="且" value="AND"></el-option>
        <el-option label="或" value="OR"></el-option>
      </el-select>
      <div class="horizontal-line"></div>
      <div class="branch-line" :style="{ height: `${item.conditions.length * 43}px` }"></div>
      <div>
        <div class="conditions-list" v-for="(subItem, subIndex) in item.conditions" :key="subItem.fieldId">
          <!-- 所有表单字段 start -->
          <el-select
            class="form-field"
            :class="{ 'form-field-err': subItem.isErr }"
            placeholder="请选择"
            filterable
            v-model="subItem.fieldId"
            @change="changeField($event, subItem)"
          >
            <el-option
              v-for="fieldItem in conditionFields"
              :key="fieldItem.fieldId"
              :label="fieldItem.title"
              :value="fieldItem.fieldId"
            ></el-option>
          </el-select>
          <!-- 所有表单字段 end -->
          <!--条件关系 start -->
          <el-select class="condition-filter" placeholder="请先选择字段" v-model="subItem.compare" @change="initFilter(subItem)">
            <el-option
              v-for="(typeItem, index) in conditionTypes[subItem.fieldName]"
              :key="`${typeItem.value}${index}`"
              :label="typeItem.label"
              :value="typeItem.value"
            ></el-option>
          </el-select>
          <!--条件关系  end -->
          <!--
        条件组件 start
         TODO: 根据字段类型动态渲染组件
           -->
          <div>
            <!--    number   -->
            <template v-if="subItem.fieldName === 'NumberInput'">
              <div :class="{ 'form-field-err': subItem.isErr }">
                <el-input
                  v-if="inputCompare.includes(subItem.compare)"
                  style="width: 225px"
                  type="number"
                  v-model.number="subItem.value[0]"
                  placeholder="请输入"
                  clearable
                />
                <template v-if="rangeCompare.includes(subItem.compare)">
                  <el-input type="number" style="width: 200px" v-model.number="subItem.value[0]" placeholder="请输入" clearable />
                  <el-input type="number" style="width: 200px" v-model.number="subItem.value[1]" placeholder="请输入" clearable />
                </template>
              </div>
            </template>

            <!--     string   -->
            <template v-if="subItem.fieldName === 'TextInput'">
              <div :class="{ 'form-field-err': subItem.isErr }">
                <el-input
                  style="width: 225px"
                  v-if="textCompare.includes(subItem.compare)"
                  v-model="subItem.value[0]"
                  placeholder="请输入"
                  clearable
                />
                <el-select
                  style="width: 225px"
                  v-if="textCompareRange.includes(subItem.compare)"
                  multiple
                  filterable
                  allow-create
                  default-first-option
                  collapse-tags-tooltip
                  :reserve-keyword="false"
                  collapse-tags
                  :max-collapse-tags="1"
                  v-model="subItem.value"
                >
                  <el-option v-for="textItem in subItem.value" :label="textItem" :value="textItem"></el-option>
                </el-select>
              </div>
            </template>

            <!--     date   -->
            <template v-if="subItem.fieldName === 'DateTime'">
              <div :class="{ 'form-field-err': subItem.isErr }">
                <el-date-picker
                  style="width: 225px"
                  v-if="subItem.compare === 'EQ'"
                  v-model="subItem.value[0]"
                  type="date"
                  value-format="YYYY-MM-DD"
                  format="YYYY-MM-DD"
                  date-format="YYYY-MM-DD"
                  placeholder="请选择"
                />
                <el-date-picker
                  v-if="subItem.compare === 'Between'"
                  v-model="subItem.value"
                  type="daterange"
                  value-format="YYYY-MM-DD"
                  format="YYYY-MM-DD"
                  date-format="YYYY-MM-DD"
                  range-separator="—"
                  start-placeholder="开始时间"
                  end-placeholder="结束时间"
                />
                <el-select style="width: 225px" v-model="subItem.value[0]" v-if="subItem.compare === 'Dynamic'">
                  <el-option v-for="selectItem in dynamicOptions" :label="selectItem.label" :value="selectItem.value"></el-option>
                </el-select>
              </div>
            </template>

            <!--     select   -->
            <template v-if="subItem.fieldName === 'SelectInput' && !['isNull', 'isNotNull'].includes(subItem.compare)">
              <div :class="{ 'form-field-err': subItem.isErr }">
                <el-select style="width: 225px" v-model="subItem.value[0]" @change="changeSelectInput($event, subItem)">
                  <el-option
                    v-for="selectItem in subItem.options"
                    :label="selectItem.label"
                    :value="selectItem.value"
                  ></el-option>
                </el-select>
              </div>
            </template>

            <!--     MultipleSelect   -->
            <template v-if="subItem.fieldName === 'MultipleSelect' && !['isNull', 'isNotNull'].includes(subItem.compare)">
              <div :class="{ 'form-field-err': subItem.isErr }">
                <el-select
                  style="width: 225px"
                  multiple
                  v-model="subItem.value"
                  allow-create
                  default-first-option
                  collapse-tags-tooltip
                  :reserve-keyword="false"
                  collapse-tags
                  :max-collapse-tags="1"
                >
                  <el-option
                    v-for="selectItem in subItem.options"
                    :label="selectItem.labelConcat || selectItem.label"
                    :value="selectItem.value"
                  ></el-option>
                </el-select>
              </div>
            </template>

            <!--    CascaderInput    -->
            <template v-if="subItem.fieldName === 'CascaderInput'">
              <div :class="{ 'form-field-err': subItem.isErr }">
                <el-cascader
                  style="width: 225px"
                  v-model="subItem.value"
                  clearable
                  :props="{
                    label: 'name',
                    value: 'cityCode'
                  }"
                  :options="cascaderOptions"
                ></el-cascader>
              </div>
            </template>
          </div>
          <!--     条件组件 end   -->
          <el-button :icon="Delete" color="#fff" @click="handelDelCondition(item, subIndex, conditionsIndex)"></el-button>
        </div>
        <el-button type="info" color="#F2F3F5" :icon="Plus" @click="handelAddCondition(item)"></el-button>
      </div>
    </div>
  </el-form>
</template>

<script setup>
/**
 * TODO:穷举,未封装
 */
import { computed, getCurrentInstance, ref } from "vue";
import { Delete, Plus } from "@element-plus/icons-vue";
import _ from "lodash";
import cascaderOptions from "@/assets/pca-code";
import { fieldList } from "@/apis/clientGroup/clientGroup";
import { selectDictDataByType, dictList } from "@/apis/dict/dict";
import {
  conditionTypes,
  inputCompare,
  rangeCompare,
  textCompare,
  textCompareRange,
  dynamicOptions
} from "@/views/clientGroup/data";
import { nonDictData } from "@/apis/clientManager";
import config from "@/settings";

const props = defineProps({
  modelValue: {
    type: Object,
    default: () => ({})
  }
});
const emit = defineEmits(["update:modalValue"]);
const { proxy } = getCurrentInstance();

const isGroupLoading = ref(false);
const formData = computed({
  get() {
    return props.modelValue;
  },
  set(val) {
    emit("update:modalValue", val);
  }
});

const inputSort = data => {
  formData.value.orderNum = data < 0 ? "" : data;
};

const dictTypes = [config.dicts.COSTEM_PREPRICE, config.dicts.COSTEM_ORIGIN];
const getDboDict = async ({ sourceValue, subItem }) => {
  try {
    isGroupLoading.value = true;
    const { data } = await selectDictDataByType(sourceValue);
    const dictData = data || [];
    subItem.options = dictData.map(item => ({
      label: item.dictLabel,
      value: item.dictValue
    }));
    isGroupLoading.value = false;
  } catch (err) {
    isGroupLoading.value = false;
  }
};
const getSaasDict = async ({ sourceValue, subItem }) => {
  try {
    isGroupLoading.value = true;
    const { data } = await dictList({ dictType: sourceValue });
    const dictData = data || [];
    subItem.options = dictData.map(item => ({
      labelConcat: dictTypes.includes(sourceValue) ? `${item.dictLabel}(${item.dictValue})` : item.dictLabel,
      label: item.dictLabel,
      value: item.dictCode
    }));
    isGroupLoading.value = false;
  } catch (err) {
    isGroupLoading.value = false;
  }
};
const getSelectOption = ({ subItem, options }) => {
  subItem.options =
    options?.map(item => ({
      label: typeof item === "number" ? (item === 0 ? "否" : "是") : item,
      value: item
    })) || [];
};
const getRemoteData = async ({ sourceValue, subItem }) => {
  try {
    isGroupLoading.value = true;
    const { data } = await nonDictData({ method: sourceValue });
    const dictData = data || [];
    let optionData = _.cloneDeep(dictData);
    if (sourceValue === "crmPortraitService.pageList()") {
      optionData = dictData.map(item => ({
        label: item.portraitName,
        value: item.portraitId
      }));
    }
    subItem.options = optionData;
    isGroupLoading.value = false;
  } catch (err) {
    isGroupLoading.value = false;
  }
};
const sourceTypes = new Map([
  ["dbo:dict", getDboDict],
  ["sass:dict", getSaasDict],
  ["select", getSelectOption],
  ["remote", getRemoteData]
]);
const getDataSource = subItem => {
  const { sourceType, sourceValue, options } = subItem.props && JSON.parse(subItem.props);
  sourceTypes.has(sourceType) ? sourceTypes.get(sourceType)({ subItem, sourceValue, options }) : (subItem.options = []);
};
const initFilter = subItem => {
  if (["DateTime", "TextInput"].includes(subItem.fieldName)) {
    subItem.value = [""];
  }
  if (subItem.fieldName === "NumberInput") {
    subItem.value = [0];
  }
  if (["MultipleSelect", "SelectInput"].includes(subItem.fieldName)) {
    // subItem.compare = "IN";
    const values = conditionTypes.MultipleSelect.map(item => item.value);
    subItem.compare = values.includes(subItem.compare) ? subItem.compare : "IN";
    subItem.value = [];
    subItem.fieldName === "SelectInput" && (subItem.value = [""]);
    getDataSource(subItem);
  }
};
const changeField = (e, subItem) => {
  subItem.compare = "EQ";
  const fieldData = conditionFields.value.find(item => item.fieldId === e);
  if (fieldData) {
    subItem.props = fieldData.props;
    subItem.fieldName = fieldData.fieldName;
    subItem.physicsName = fieldData.physicsName;
    initFilter(subItem);
  }
};

const changeSelectInput = (e, subItem) => {
  const label = subItem.options?.find(item => item.value === e)?.label;
  subItem.label = label ? [label] : [];
};

const handelAddGroup = () => {
  formData.value.conditions.push({
    groupType: "AND",
    conditions: [
      {
        fieldName: "",
        fieldId: "",
        compare: "",
        value: []
      }
    ]
  });
};
const handelAddCondition = item => {
  item.conditions.push({
    fieldName: "",
    fieldId: "",
    compare: "",
    value: []
  });
};
const handelDelCondition = (item, index, conditionsIndex) => {
  item.conditions.splice(index, 1);
  if (!item.conditions?.length) {
    formData.value.conditions.splice(conditionsIndex, 1);
  }
};

const conditionFields = ref([]);
const getFieldList = async () => {
  try {
    const { data } = await fieldList();
    conditionFields.value = data || [];
  } catch (err) {
    console.log(err);
  }
};

// TODO:后续在优化
const submit = () => {
  return new Promise((resolve, reject) => {
    try {
      proxy.$refs.formRef.validate(val => {
        let result = val;
        if (val) {
          result = true;
          formData.value.conditions.forEach(item => {
            if (item.conditions?.length) {
              item.conditions.forEach(subItem => {
                let labelData = [];
                //处理多选
                if (subItem.fieldName === "MultipleSelect") {
                  const params = subItem.options?.filter(filterItem => subItem.value.includes(filterItem.value));
                  labelData =
                    params?.map(item => {
                      return item.label;
                    }) || [];
                } else if (subItem.fieldName === "SelectInput") {
                  const label = subItem.options?.find(labelItem => subItem.value.includes(labelItem.value))?.label;
                  labelData = label ? [label] : [];
                } else {
                  labelData = subItem.value;
                }

                if (subItem.compare === "isNull") {
                  subItem.value = ["isNull"];
                  labelData = ["isNull"];
                }
                if (subItem.compare === "isNotNull") {
                  subItem.value = ["isNotNull"];
                  labelData = ["isNotNull"];
                }
                subItem.label = labelData;
                subItem.isErr = false;
                /**
                 * TODO:确实写得像一坨,不重要,先要能用再说
                 */
                if (!subItem.fieldName || !subItem.fieldId || !subItem.compare || !subItem.value?.length) {
                  result = false;
                  subItem.isErr = true;
                }
                if (subItem.value?.length) {
                  if (["DateTime", "TextInput", "SelectInput", "NumberInput"].includes(subItem.fieldName)) {
                    if (subItem.fieldName === "DateTime") {
                      const resultFilter = subItem.value.filter(item => item !== 0 && !item);
                      if (resultFilter.length) {
                        result = false;
                        subItem.isErr = true;
                      }
                    }
                    if (subItem.value[0] !== 0 && !subItem.value[0]) {
                      result = false;
                      subItem.isErr = true;
                    }
                  }
                  if (["MultipleSelect"].includes(subItem.fieldName)) {
                    const resultFilter = subItem.value.filter(item => item !== 0 && !item);
                    if (resultFilter.length) {
                      result = false;
                      subItem.isErr = true;
                    }
                  }
                }
              });
            }
          });
        }
        resolve(result);
      });
    } catch (err) {
      reject(err);
    }
  });
};

defineExpose({
  submit
});

getFieldList();
</script>

<style scoped lang="scss">
@use "@/assets/styles/mixin";

// TODO:  通用样式
:deep(.el-input__wrapper),
:deep(.el-select__wrapper),
:deep(.el-textarea__inner),
:deep(.el-input__count),
:deep(.el-input__count-inner) {
  background-color: #f2f3f5 !important;
}

.group-name {
  display: flex;
  display: -webkit-flex;
  align-items: baseline;
  :deep(.el-form-item) {
    margin-bottom: 0 !important;
  }
  &_input {
    :deep(.el-input) {
      width: 700px;
    }
  }
  &_tip {
    margin-bottom: 20px;
    padding-left: 79px;
    font-weight: 400;
    font-size: 12px;
    color: #86909c;
    line-height: 22px;
  }
  &_tel {
    margin-bottom: 0px !important;
    :deep(.el-form-item__content) {
      margin-left: 0px !important;
    }
  }
  :deep(.el-form-item__error) {
    position: static;
  }
}

.group-container {
  @include mixin.flex-align;
  .horizontal-line {
    width: 16px;
    height: 1px;
    background-color: #e5e6eb;
  }
  .branch-line {
    width: 16px;
    height: 42px;
    border: 1px solid #e5e6eb;
    border-right: 0;
  }
  & + .group-container {
    margin-top: 30px;
  }
}

.group-not-type {
  @include mixin.flex-inline-flex;
  width: 60px;
  height: 32px;
  background-color: #f2f3f5;
  border-radius: 4px;
  box-shadow: 0 0 0 1px #dcdfe6 inset;
}
.group-type {
  width: 60px;
  :deep(.el-select__wrapper) {
    width: 60px;
  }
}

.conditions-list {
  @include mixin.flex-align;
  flex-wrap: nowrap;
  gap: 10px;
  margin-bottom: 10px;
  .form-field {
    width: 200px;
  }
  .form-field-err {
    border: 1px solid var(--el-color-danger);
    border-radius: 4px;
  }
  .condition-filter {
    width: 150px;
  }
}
</style>
